<script setup lang="ts">
import {onBeforeUnmount, onMounted, reactive, ref, shallowRef} from "vue";
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import {Editor, Toolbar} from '@wangeditor/editor-for-vue'
import {IDomEditor} from '@wangeditor/editor'
import type {FormInstance, FormRules, UploadFile, UploadFiles} from 'element-plus'
import {ElMessage, ElMessageBox} from 'element-plus'
import {transformElTree} from "@/utils/tree";
import {useRouter} from 'vue-router'
import {ArticlePublishReq} from "@/api/article/types";
import {getArticleCategoryTree, publishNewArticle, saveArticleDraft} from "@/api/article";
import * as FileApis from "@/api/file";
import * as FileApiTypes from "@/api/file/types";
import {isEmptyString} from "@/utils/string";
import {generateThumbnail} from "@/utils/image";

const router = useRouter()

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef()
const isFocused = ref(false)
const articleFormRef = ref<FormInstance>()
const selectedCoverFiles = ref([])
const coverImageURL = ref(null)
const articleForm = reactive<ArticlePublishReq>({
  title: '',
  summary: '',
  content: '',
  categoryId: null,
  coverImage: null,
  tags:[]
})


const categoryTree = ref([]);

const articleFormRules = reactive<FormRules<ArticlePublishReq>>({
  title: [
    {required: true, message: '请填写文章标题', trigger: 'blur'},
    {min: 1, max: 100, message: '长度请限制在1-100', trigger: 'blur'},
  ],
  content: [
    {required: true, message: '请填写文章详情', trigger: 'blur'},
    {min: 10, max: 2000, message: '长度请限制在10-2000', trigger: 'blur'},
  ],
  categoryId: [
    {required: true, message: '请选择分类', trigger: 'change'},
  ]
})
type InsertFnType = (url: string, alt: string, href: string) => void
const editorConfig = {
  MENU_CONF: {
    uploadImage: {
      server: '/api/funhub/file/upload',
      fieldName: 'file',
      maxFileSize: 5 * 1024 * 1024, // 单个文件的最大体积限制1M
      maxNumberOfFiles: 1,
      meta: {
        businessType: 'articleImage'
      },
      allowedFileTypes: ['image/*'],
      customInsert: (res: any, insertFn: InsertFnType) => {
        insertFn(FileApis.getDownloadUrl(res.data.fileId), res.data.fileId, '#')
      },
      onSuccess(file: File, res: any) {
        uploadSuccessImageFiles.push({fileId: res.data.fileId, file : file?.data})
      },
      onFailed: (file: File, res: any) => {
        ElMessage.error(`${file.name} 上传失败`)
      },
      onError: (file: File, res: any) => {
        ElMessage.error(`${file.name} 上传失败`)
      }
    },
    placeholder: '请输入内容...',
    autoFocus: false,
    maxLength: 2000
  }
}
const uploadSuccessImageFiles : {fileId:string, file:File}[] = []

const handleEditorCreated = (editor) => {
  editorRef.value = editor // 记录 editor 实例，重要！
}

const onEditorMaxLength = (editor: IDomEditor) => {
  ElMessageBox.alert('超出最大长度限制', '提示', {
    confirmButtonText: '知道了'
  })
}
const loadCategoryTreeSelect = () => {
  getArticleCategoryTree().then(result => {
    categoryTree.value = transformElTree(result)
  })
}

const saveDraft = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.validate((valid, fields) => {
    if (valid) {
      saveArticleDraft(articleForm).then((result) => {
        ElMessage({
          type: 'success',
          message: "保存成功"
        })
      })
    }
  })
}

const publish = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.validate(async (valid, fields) => {
    if (valid) {
      //摘要截取前200字符
      articleForm.summary = editorRef.value.getText().slice(0, 200)
      //取第一张图片作为封面
      if (isEmptyString(articleForm.coverImage)) {
        let imageElems = editorRef.value.getElemsByType('image')
        if (Array.isArray(imageElems) && imageElems.length > 0) {
          let firstImageFile : File = uploadSuccessImageFiles.filter(file => file.fileId == imageElems[0].alt)[0].file
          if (firstImageFile && firstImageFile.size > 500 * 1024) {
            let firstImageThumbnail = await generateThumbnail(firstImageFile, {
              maxWidth: 400,
              maxHeight: 400,
              mimeType: firstImageFile.type,
              quality: 0.9
            });
            let result = await FileApis.upload(firstImageThumbnail, FileApiTypes.BusinessType.ARTICLES_COVER)
            articleForm.coverImage = result.fileId
          } else {
            articleForm.coverImage = imageElems[0].alt
          }
        }
      }

      publishNewArticle(articleForm).then((result) => {
        router.replace({path: '/article/detail/' + Number(result)})
        ElMessage({
          type: 'success',
          message: "发布成功"
        })
      })
    }
  })
}
const handleCoverImageUpload = async (uploadFile: UploadFile)=>{
  const isImage = uploadFile.raw.type.startsWith('image/'); // 检查 MIME 类型
  if (!isImage) {
    ElMessage.warning('只能上传图片文件！');
    return
  }
  if (uploadFile.size > 5 * 1024 * 1024) {
    ElMessage.warning('上传图片文件不能大于5M！');
    return
  }
  let finalFile : File = uploadFile.raw
  //生成缩略图
  if (uploadFile.size > 500 * 1024) {
    finalFile = await generateThumbnail(uploadFile.raw, {maxWidth: 400, maxHeight: 400, mimeType: uploadFile.raw.type, quality: 0.9})
  }
  FileApis.upload(finalFile, FileApiTypes.BusinessType.ARTICLES_COVER).then(result => {
    articleForm.coverImage = result.fileId
    coverImageURL.value = URL.createObjectURL(finalFile)
  })
}

onMounted(() => {
  loadCategoryTreeSelect()
})

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor != null) {
    setTimeout(() => editor.destroy(), 200)
  }
})
</script>

<template>
  <div class="w-full h-full overflow-auto bg-white-soft">
    <div class="mt-6">
      <div class="ui FHContainer">
        <div class="FHMain">
          <div class="FHContent flex flex-row">
            <div class="content">
              <h1 class="text-3xl font-bold text-center mb-8">发布新文章</h1>
              <el-form class="p-6" ref="articleFormRef" :model="articleForm" label-width="auto"
                       label-position="top" size="large"
                       :rules="articleFormRules">
                <el-form-item label="文章标题" prop="title">
                  <el-input v-model="articleForm.title" placeholder="请输入文章标题" autofocus/>
                </el-form-item>
                <el-form-item label="文章详情" prop="content">
                  <div class="rounded-lg overflow-hidden" style="border: 1px solid var(--el-border-color);"
                       :class="{'input-focus': isFocused}">
                    <Toolbar
                        style="border-bottom: 1px solid var(--el-border-color)"
                        :editor="editorRef"
                        :defaultConfig="{excludeKeys:['fullScreen']}"
                        mode="default"
                    />
                    <Editor
                        style="height: 800px; overflow-y: hidden;"
                        v-model="articleForm.content"
                        :defaultConfig="editorConfig"
                        mode="default"
                        @onCreated="handleEditorCreated"
                        @onFocus="isFocused = true"
                        @onBlur="isFocused = false"
                        @onMaxLength="onEditorMaxLength"
                    />
                  </div>
                </el-form-item>
                <el-form-item label="分类" prop="categoryId" label-position="left">
                  <el-tree-select
                      v-model="articleForm.categoryId"
                      :data="categoryTree"
                      :render-after-expand="false"
                      style="width: 240px"
                      placeholder="请选择分类"
                  />
                </el-form-item>
                <el-form-item label="标签" prop="tags" label-position="left">
                  <el-input-tag
                      v-model="articleForm.tags"
                      tag-type="primary"
                      placeholder="文章关键词，使用回车换行键确定，可选填"
                      clearable
                  ></el-input-tag>
                </el-form-item>

                <el-form-item label="封面图片（不设置时默认选取文章的第一张图片）" prop="coverImage">
                  <el-upload
                      class="coverImage-uploader"
                      v-model:file-list="selectedCoverFiles"
                      accept="image/*"
                      :auto-upload="false"
                      :show-file-list="false"
                      :on-change="handleCoverImageUpload"
                  >
                    <img v-if="coverImageURL" :src="coverImageURL" />
                    <el-icon v-else class="coverImage-uploader-icon">
                      <Plus/>
                    </el-icon>
                  </el-upload>
                </el-form-item>
                <!-- 提交按钮 -->
                <div class="flex justify-end">
                  <el-button @click="saveDraft(articleFormRef)">保存草稿</el-button>
                  <el-button type="primary" @click="publish(articleFormRef)">发布</el-button>
                </div>
              </el-form>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style>
.input-focus {
  border-color: var(--el-color-primary) !important;
}

.coverImage-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.coverImage-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.coverImage-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>